﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DbSharp.ConsoleRunner.Parser;
using System.IO;
using DbSharp.Framework.TestEngine;
using DbSharp.Framework.CaseFile.Parser;
using DbSharp.Framework.ReleaseManage;

namespace DbSharp.ConsoleRunner
{
    class Program
    {
        internal Options options = new Options();
        internal CommandLineParser parser = new CommandLineParser();
        internal string TestFile { get; set; }
        private TestReport m_TestReport = new TestReport();

        public void Parse(string[] args)
        {
            try
            {
                parser.AdditionalArgumentsSettings.RequestedAdditionalArgumentsCount = 1;
                parser.ExtractArgumentAttributes(options);
                parser.ParseCommandLine(args);

                if (parser.AdditionalArgumentsSettings.AdditionalArguments.Length != 1)
                {
                    options.ShowHelp = true;
                }
                else
                {
                    TestFile = parser.AdditionalArgumentsSettings.AdditionalArguments[0];
                    if (!File.Exists(TestFile))
                        options.ShowHelp = true;
                }
            }
            catch (Exception)
            {
                options.ShowHelp = true;
            }
#if DEBUG
            Console.WriteLine(TestFile);
            Console.WriteLine(options.ShowHelp);
            Console.WriteLine(string.Join(",", options.CaseNames.ToArray()));
            Console.WriteLine(string.Join(",", options.Tags.ToArray()));
            Console.WriteLine(options.Export);
            Console.WriteLine(options.Log);
            Console.WriteLine(options.PerformanceTest);
            Console.WriteLine(options.UnitTest);
            Console.WriteLine(options.Silent);
#endif
        }

        public bool ShowUsage
        {
            get { return options.ShowHelp; }
        }

        public void PrintUsage()
        {
            parser.ShowUsage();
        }






        static int Main(string[] args)
        {
            Program p = new Program();
            p.Parse(args);
            if (p.ShowUsage)
            {
                p.PrintUsage();
                return 1;
            }
            else
            {
                bool passed = p.RunCore();
                if (passed)
                    return 0;
                else
                    return 1;
            }

        }

        private bool RunCore()
        {
            CaseTestState overallResult = CaseTestState.NotRun;
            m_TestReport.BeginReport();
            try
            {
                List<TestRunnerBase> list = LoadCase();

                CaseRunType type = options.Export ? CaseRunType.ExportXml : CaseRunType.Test;
                CompositeTestCaseStatusNotify statusNotifier = new CompositeTestCaseStatusNotify();
                if (!options.Silent)
                    statusNotifier.Add(new ConsoleTestStatusNotifier());
                if (options.Log != null)
                    statusNotifier.Add(new LogTestStatusNotifier(options.Log));

                foreach (var item in list)
                {
                    item.Run(type, statusNotifier);
                    m_TestReport.EndTestCase(item);
                }

                m_TestReport.EndReport();
                ITestReportNotify testReportNotifier = new ConsoleTestReportNotifier();
                testReportNotifier.UpdateStatus(m_TestReport);
                overallResult = m_TestReport.GetUnitTestsOverallTestState();
                if (overallResult == CaseTestState.Failed)
                    return false;
                else
                    return true;
            }
            catch
            {
                return false;
            }
        }

        private List<TestRunnerBase> LoadCase()
        {
            ICaseFileLoadedNotify notifier = null;
            if (!options.Silent)
            {
                notifier = new ConsoleCaseFileLoadedNotify();
            }
            CaseFileLoader loader = new CaseFileLoader(new CaseFileParser(notifier, TestFile));
            List<TestRunnerBase> list = new List<TestRunnerBase>();
            if (!options.PerformanceTest)
                list.AddRange(from t in loader.LoadUnitCaseRunners()
                              where IsCaseNameEquals(t) && IsTagEquals(t)
                              select (TestRunnerBase)t);
            if (!options.UnitTest)
                list.AddRange(from t in loader.LoadPerfCaseRunners()
                              where IsCaseNameEquals(t) && IsTagEquals(t)
                              select (TestRunnerBase)t);
            return list;
        }

        private bool IsCaseNameEquals(TestRunnerBase t)
        {
            if (options.CaseNames == null || options.CaseNames.Count == 0)
                return true;
            foreach (var name in options.CaseNames)
                if (string.Equals(t.CaseName, name, StringComparison.CurrentCultureIgnoreCase))
                    return true;
            return false;
        }

        private bool IsTagEquals(TestRunnerBase t)
        {
            if (options.Tags == null || options.Tags.Count == 0)
                return true;
            if (string.IsNullOrEmpty(t.Tags))
                return false;
            HashSet<string> tags = new HashSet<string>(t.Tags.Split(','),
                StringComparer.CurrentCultureIgnoreCase);
            return tags.Overlaps(options.Tags);
        }

    }
}
